package com.example.Nurse_Notifier;

import android.app.*;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.media.MediaPlayer;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Vibrator;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.*;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import interfaces.ChangeState;
import interfaces.NotifyUser;

import java.net.SocketException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends FragmentActivity implements ActionBar.TabListener,
        NotifyUser {

    private ActionBar actionBar;
    private ViewPager mViewPager;
    private WifiManager wifiManager;
    private WifiConfigurator wifiConfigurator;
    private Vibrator vibrator;
    private PackageAnalyzer packageAnalyzer;
    private boolean isAlreadyNotified = false;
    private boolean isAlreadyNotifiedAlarm = false;
    private MediaPlayer mediaPlayer;
    private int currentItem = -1;
    private int devsCnt = 0;
    private final int SCHEDULED_START = 3000;
    private int currentTab = -1;
    private int previousTab = -1;
    private static int OUT_PORT = 21214;
    private static int IN_PORT = 21215;
    private WindowFragmentAdapter fragmentAdapter;
    private Thread th;
    private UdpServer udpServer;
    private XbeeDeviceContainer xbeeDeviceContainer;
    private HistContainer histContainer;
    private ArrayList<NotifyUser> notifyUsers;

    private boolean isShowing;
    private boolean isOff = false;
    private boolean isPeculiarDevice = false;
    private boolean onPause = false;
    private boolean isAlarmOff = false;

    final byte[] adr = {10, 11, 14, (byte) 247};
    final byte[] dropAddr = {(byte) 192, (byte) 168, (byte) 217, 2};
    final byte[] visitors1 = {10, 11, 14, 55};
    final byte[] visitors2 = {10, 11, 15, (byte) 172};

    final long[] alarmPattern = {1000, 500, 500, 1000, 500, 1000, 500, 1000, 500};

    private ArrayList<ChangeState> changeStatesListeners;
    private Timer timer;

    Thread showTh = new Thread(new Runnable() {
        @Override
        public void run() {
            if (isShowing()) {
                devsCnt = udpServer.getDevicesCnt(true);
                Log.i("SK", "Devs cnt -> " + devsCnt);
                if (devsCnt == -1) {
                    devsCnt = udpServer.getDevicesCnt(true);
                }
                if (devsCnt > -1) {
                    if (devsCnt != 0) {
                        byte[] val = udpServer.customRequest(UdpServer.ADD_OLOL, 9, 0, 0, null);
                        showToast("Reg olol device");
                        if (val != null) {
                            isPeculiarDevice = true;
                            showToast("Olol device registered");
                        } else {
                            showToast("Failed to register olol device, try to do that one more time");
                            val = udpServer.customRequest(UdpServer.ADD_OLOL, 9, 0, 0, null);
                            isPeculiarDevice = val != null;
                        }

                    } else {
                        showToast("Зарегистрированные на сервере устройства отсутствуют");
                    }

                } else {
                    showToast("Сервер недоступен");
                }
            }
            setOff(true);
        }
    });

    Thread checkTh = new Thread(new Runnable() {
        @Override
        public void run() {
            while (udpServer.isRunning()) {
                if (DeviceActivity.isStatusChanged()) {
                    Log.i("SK", "Device status has been changed in device activity");
                    int[] data = DeviceActivity.getData();
                    Log.i("SK", "DATA IN DEVICE ACTIVITY -> " + Arrays.toString(data));
                    if (data != null) {
                        if (data[0] > -1) {
                            udpServer.setDeviceStatus(data[0], data[1]);
                            DeviceActivity.setIsChanged(false);
                        } else {
                            showToast("Index out of bounds");
                        }
                    } else {
                        Log.i("SK", "Data is null");
                    }
                }
            }
        }
    });

    class ScheduledTask extends TimerTask {

        @Override
        public void run() {
            while (!isOff()) {
            }
            for (int i = 0; i < devsCnt; i++) {
                udpServer.getDeviceMacAddress(i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                udpServer.getDeviceStatus(i);
            }
            timer.cancel();
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        actionBar = getActionBar();
        actionBar.setDisplayShowHomeEnabled(false);
        actionBar.setDisplayShowTitleEnabled(false);
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        xbeeDeviceContainer = new XbeeDeviceContainer();
        histContainer = new HistContainer();

        try {
            udpServer = new UdpServer(dropAddr, IN_PORT, OUT_PORT, this);
        } catch (SocketException e) {
            e.printStackTrace();
        }

        fragmentAdapter = new WindowFragmentAdapter(getSupportFragmentManager(), this, xbeeDeviceContainer,
                histContainer);

        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(fragmentAdapter);

        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                actionBar.setSelectedNavigationItem(position);
            }
        });

        for (int i = 0; i < fragmentAdapter.getCount(); i++) {
            actionBar.addTab(
                    actionBar.newTab()
                            .setText(fragmentAdapter.getPageTitle(i))
                            .setTabListener(this));
        }

        currentTab = actionBar.getTabAt(1).getPosition();
        previousTab = currentTab;
        mViewPager.setCurrentItem(currentTab);

        wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        wifiConfigurator = new WifiConfigurator(wifiManager);
        if (!wifiConfigurator.checkWiFiState()) {
            leaveDialog();
        } else {

            changeStatesListeners = new ArrayList<ChangeState>();
            notifyUsers = new ArrayList<NotifyUser>();
            notifyUsers.add(this);
            notifyUsers.add(fragmentAdapter.getHistFragment());
            changeStatesListeners = fragmentAdapter.getChangeStates();
            packageAnalyzer = new PackageAnalyzer
                    (changeStatesListeners, xbeeDeviceContainer, this, notifyUsers);

            udpServer.addListener(packageAnalyzer);
            vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);

            th = new Thread(udpServer);
            th.start();

            timer = new Timer(true);
            timer.schedule(new ScheduledTask(), SCHEDULED_START);

            showTh.start();
            setShowing(true);
            checkTh.start();
        }
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {

            case R.id.settings: {
                startNewActivity(new SettingsActivity());
                break;
            }

            case R.id.exit: {
                finish();
                System.exit(0);
                break;
            }
            case R.id.set_to_idle: {
                int curItem = fragmentAdapter.getListFragment().getCurrentPos();
                boolean devStatus = udpServer.setDeviceStatus(curItem, UdpServer.DEVICE_IDLE);
                showToast("Have the status been setted? ->  " + devStatus);
                break;
            }

            case R.id.turn_button_off: {
                boolean buttonStatus = udpServer.setButtonStatus(fragmentAdapter.getListFragment().
                        getItemAdapter().currentItem, false);
                showToast("Turning off the button in menu ->  " + buttonStatus);
                break;
            }
            case R.id.about: {
                Toast.makeText(MainActivity.this, "This program was created by -> ", Toast.LENGTH_SHORT).show();
                break;
            }

            case R.id.get_status: {
                int curItem = fragmentAdapter.getListFragment().getCurrentPos();
                int status = udpServer.getDeviceStatus(curItem);
                showToast("Device status -> " + udpServer.getStatusById(status) + " Status: " + status);
                break;
            }

            case R.id.get_devs_cnt: {
                int devcnt = udpServer.getDevicesCnt(false);
                showToast("Devices count -> " + devcnt);
                break;
            }

            case R.id.set_scan: {
                int curItem = fragmentAdapter.getListFragment().getCurrentPos();
                boolean status = udpServer.setDeviceStatus(curItem, UdpServer.DEVICE_SCAN);
                showToast("Have the status been set? ->  " + status);
                break;
            }
            default:
                return super.onOptionsItemSelected(item);
        }
        return true;
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_BACK: {
                if (!onPause) {
                    if (currentTab != previousTab) {
                        mViewPager.setCurrentItem(previousTab);
                        int temp = currentTab;
                        currentTab = previousTab;
                        previousTab = temp;
                    } else {
                        messageDialogue();
                    }
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    }

    @Override
    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
        currentTab = tab.getPosition();
        mViewPager.setCurrentItem(currentTab, true);
    }

    @Override
    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    }

    public void messageDialogue() {

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        LayoutInflater inflater = this.getLayoutInflater();
        View v = inflater.inflate(R.layout.leavelayout, null);
        builder.setView(v);
        builder.setTitle("Выход из приложения..");
        builder.setPositiveButton("Ок", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                closeApp();
            }
        });
        builder.setNegativeButton("Отмена", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        builder.show();
    }

    public void leaveDialog() {
        Dialog dialog = new Dialog(MainActivity.this);
        dialog.setContentView(R.layout.maindialogue);
        dialog.setTitle("Сеть недоступна...");
        dialog.setCancelable(false);
        dialog.setCanceledOnTouchOutside(false);
        TextView text = (TextView) dialog.findViewById(R.id.TextView01);
        text.setText(R.string.lost_of_text);

        ImageView img = (ImageView) dialog.findViewById(R.id.ImageView01);
        img.setImageResource(R.drawable.nista_logo);
        Button button = (Button) dialog.findViewById(R.id.Button01);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                closeApp();
            }
        });
        dialog.show();
    }

    public void buttonDialog(final int deviceNum) {
        final Dialog dialog = new Dialog(MainActivity.this);
        dialog.requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
        dialog.setContentView(R.layout.warning_dialog);
        dialog.getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title);
        dialog.setCancelable(false);
        dialog.setCanceledOnTouchOutside(false);

        TextView textView = (TextView) dialog.findViewById(R.id.warningTV);
        textView.setText("На устройстве №" + deviceNum + " нажата кнопка срочного вызова. Пациенту необходима помощь." +
                "");
        ImageView imageView = (ImageView) dialog.findViewById(R.id.warningIV);
        imageView.setImageResource(R.drawable.dead_man_image_small);

        Button button = (Button) dialog.findViewById(R.id.warningOkButton);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                boolean status = udpServer.setButtonStatus(deviceNum - 1, false);
                showToast("Setting button status to false -> " + status);
                vibrator.cancel();
                dialog.cancel();
                isAlreadyNotified = false;
            }
        });
        dialog.show();
    }

    public void alarmDialog(final int deviceNum) {
        final Dialog dialog = new Dialog(MainActivity.this);
        dialog.requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
        dialog.setContentView(R.layout.warning_dialog);

        dialog.getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title);
        dialog.setCancelable(false);
        dialog.setCanceledOnTouchOutside(false);


        TextView textView = (TextView) dialog.findViewById(R.id.warningTV);
        textView.setText("Инфузионное вливание в капельнице №" + deviceNum + " завершено. " +
                "Необходимо подойти к пациенту.");
        ImageView imageView = (ImageView) dialog.findViewById(R.id.warningIV);
        imageView.setImageResource(R.drawable.red_warning_sign_small);

        Button button = (Button) dialog.findViewById(R.id.warningOkButton);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mediaPlayer.stop();
                vibrator.cancel();
                dialog.cancel();
                isAlarmOff = udpServer.setDeviceStatus(deviceNum - 1, UdpServer.DEVICE_IDLE);
                isAlreadyNotifiedAlarm = false;
            }
        });
        dialog.show();
    }

    public void showToast(final String data) {
        MainActivity.this.runOnUiThread(new Runnable() {
            public void run() {
                Toast.makeText(MainActivity.this, data, Toast.LENGTH_LONG).show();
            }
        });
    }

    @Override
    public void notifyButtonPressed(final int devNum, boolean isPressed) {
        if (isPressed) {
            if (!isAlreadyNotified) {
                isAlreadyNotified = true;
                currentItem = devNum;
                vibrator.vibrate(alarmPattern, 1);
                this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        buttonDialog(devNum + 1);
                    }
                });
            }
        }
    }

    @Override
    public void notifyAlarm(final int devNum) {
        if (onPause) {
            alarm(devNum);
        } else {
            alarm(devNum);
        }
    }

    public void closeApp() {
        if (isPeculiarDevice) {
            udpServer.customRequest(UdpServer.REM_OLOL, 9, 0, 0, null);
        }
        finish();
        System.exit(0);
    }

    public void startNewActivity(Activity activityToStart) {
        Intent intent = new Intent(this, activityToStart.getClass());
        startActivity(intent);
    }

    public boolean isShowing() {
        return isShowing;
    }

    public void setShowing(boolean isShowing) {
        this.isShowing = isShowing;
    }

    public boolean isOff() {
        return isOff;
    }

    public void setOff(boolean isOff) {
        this.isOff = isOff;
    }

    public void alarm(final int devNum) {
        Log.i("SK", "Notify user (Main activity) before thread");
        if (!isAlarmOff) {
            if (!isAlreadyNotifiedAlarm) {
                isAlreadyNotifiedAlarm = true;
                mediaPlayer = MediaPlayer.create(MainActivity.this, R.raw.beep_alarm);
                mediaPlayer.start();
                mediaPlayer.setLooping(true);
                vibrator.vibrate(alarmPattern, 1);
                this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Log.i("SK", "Notify user (Main activity) inside thread");
                        alarmDialog(devNum + 1);
                    }
                });
            }
        } else {
            isAlarmOff = false;
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        onPause = true;
    }

    @Override
    protected void onResume() {
        super.onResume();
        onPause = false;
    }
}